class Solution
{
public:
    double minAreaFreeRect(vector<vector<int>> &points)
    {
        int nPoints = points.size();
        unordered_map<int, unordered_set<int>> pointsByX;
        for (auto &point : points)
        {
            pointsByX[point[0]].insert(point[1]);
        }

        auto checkVertical = [](vector<int> &vertex, vector<int> &sidePoint1, vector<int> &sidePoint2) -> bool
        {
            long long vector1_x = sidePoint1[0] - vertex[0];
            long long vector1_y = sidePoint1[1] - vertex[1];
            long long vector2_x = sidePoint2[0] - vertex[0];
            long long vector2_y = sidePoint2[1] - vertex[1];
            return vector1_x * vector2_x + vector1_y * vector2_y == 0LL;
        };

        auto checkOppositeVertexExist = [&](vector<int> &vertex, vector<int> &sidePoint1, vector<int> &sidePoint2) -> bool
        {
            int opposite_x = sidePoint1[0] + sidePoint2[0] - vertex[0];
            int opposite_y = sidePoint1[1] + sidePoint2[1] - vertex[1];
            return pointsByX.count(opposite_x) && pointsByX[opposite_x].count(opposite_y);
        };

        auto calcArea = [](vector<int> &vertex, vector<int> &sidePoint1, vector<int> &sidePoint2) -> double
        {
            long long vector1_x = sidePoint1[0] - vertex[0];
            long long vector1_y = sidePoint1[1] - vertex[1];
            long long vector2_x = sidePoint2[0] - vertex[0];
            long long vector2_y = sidePoint2[1] - vertex[1];
            return sqrt(vector1_x * vector1_x + vector1_y * vector1_y) *
                   sqrt(vector2_x * vector2_x + vector2_y * vector2_y);
        };

        double minArea = 1e308;
        for (int i = 0; i < nPoints; ++i)
        {
            for (int j = 0; j < nPoints; ++j)
            {
                if (i == j)
                {
                    continue;
                }
                for (int k = 0; k < nPoints; ++k)
                {
                    if (k == i || k == j)
                    {
                        continue;
                    }
                    auto &p1 = points[i];
                    auto &p2 = points[j];
                    auto &p3 = points[k];
                    if (checkVertical(p1, p2, p3))
                    {
                        if (checkOppositeVertexExist(p1, p2, p3))
                        {
                            minArea = min(minArea, calcArea(p1, p2, p3));
                        }
                    }
                }
            }
        }
        return minArea > 1e307 ? 0.0 : minArea;
    }
};